#include "test_queues.h"
#include "queue.h"
#include "os_io.h"
#include "process.h"
#include "os_mem.h"

static q_id_t low_prio_q_id;
static q_id_t high_prio_q_id;

/*
* Spawn low priority process
*
* Low priority process spawns high priority process
* High priority process creates a queue and blocks on it
* Low priority process resumes and creates a queue.
* Low priority process enqueue to high priority process
* High prirority process resumes, enqueues and sends 10 messages to low priority process
* High priority process blocks on its queue
* Low priority process dequeues all 10 messages from its queue
* Low priroty process sends reply to high priority process
* High priority process resumes, deletes its queue ane terminates.
* Low priority process resumes, deletes its queue and terminates.
*/


void high_queue(void)
{
    queue_handle_t q_handle;
    err_t err_code;
    uint32_t data = 0;
    queue_msg_t q_msg;
    uint8_t i = 0;

    printf("2. High priority process started\n");

    err_code = create_queue((const uint8_t *)"high_prio_queue", NULL, &q_handle);
    printf("3. High priority process created queue with err_code: 0x%x\n", err_code);
    if (err_code != ERR_SUCCESS) {
        return;
    }

    printf("4. High prio process queue id: 0x%x\n", q_handle->queue_id);

    printf("5. High priority process blocking on its queue\n");
    err_code = dequeue(q_handle, &q_msg);
    printf("9. High prirority process dequeued 0x%x from the queue. Error code: 0x%x\n", *(uint32_t *)q_msg.msg_data,
      err_code);

    err_code = lookup_queue((const uint8_t *)"low_prio_queue", &low_prio_q_id);
    printf("9.5. High prioirity process fetched low prio queue. err:0x%x, q_id:0x%x\n", err_code, low_prio_q_id);

    for (i = 0; i < 10; i++) {

       data = 0xABAB0000 + i;
       printf(" 10. High priority process enqueuing 0x%x to low priority process", data);
       err_code = enqueue(low_prio_q_id, (void *)&data, sizeof(data));
       printf("10. High priority process resume after 0x%xth enqueue. Error code: 0x%x\n", i,
            err_code);
   }

   printf("11. High priority process blocking on its queue again\n");
   err_code = dequeue(q_handle, &q_msg);
   printf("14. High prirority process dequeued 0x%x from the queue. Error code: 0x%x\n", *(uint32_t *)q_msg.msg_data,
           err_code);

   err_code = destroy_queue(q_handle);
   printf("15. High priority process destroyed its queue. Terminating...\n");

   return;
}


void low_queue(void)
{
    queue_handle_t q_handle;
    err_t err_code;
    uint32_t data = 0;
    queue_msg_t q_msg;
    uint8_t i = 0;

    printf("0. Low priority process started\n");

    printf("1. Low priority process spawning high priority process\n");
    exec_mem(high_queue, (const uint8_t *)"high queue", 0, 9);
    
    err_code = create_queue((const uint8_t *)"low_prio_queue", NULL, &q_handle);
    printf("6. Low priority process created queue with err_code: 0x%x\n", err_code);
    if (err_code != ERR_SUCCESS) {
        return;
    }

    err_code = lookup_queue((const uint8_t *)"high_prio_queue", &high_prio_q_id);
    printf("7. Low priority process fetched high prio queue-id. err:0x%x, q_id:0x%x\n", err_code, high_prio_q_id);
    

    data = 0xABCDABCD;
    printf("8. Low priority process enqueueing 0x%x to high priority process\n", data);
    err_code = enqueue(high_prio_q_id, (void *)&data, sizeof(data));
    printf("Low priority process resume. Err code for enqueue: 0x%x\n", err_code);

    for (i = 0; i < 10; i++) {

       printf("12. Low priority process blocking on queue for the 0x%x'th time\n", i);
       err_code = dequeue(q_handle, &q_msg);
       printf("12. Low priority process dequeued 0x%x from the queue. Error code: 0x%x\n", *(uint32_t *)q_msg.msg_data,
            err_code);
       free(q_msg.msg_data);
   }

   printf("13. Low priority message sending final reply to high priority process: 0x%x\n", data);
   err_code = enqueue(high_prio_q_id, (void *)&data, sizeof(data));
   printf("16. Low priority process resume after sending reply. Err_code: 0x%x\n", err_code);

   err_code = destroy_queue(q_handle);
   printf("17. Low priority process destroyed its queue. Terminating...\n");

   return;
}


void test_queues(void)
{

  printf("Running queues test\n");
  exec_mem(low_queue, (const uint8_t *)"low queue", 0, 10);

}
